package com.ctsi.system.service;

import com.ctsi.commons.util.UtilDateTime;
import com.ctsi.commons.util.response.Page;
import com.ctsi.framework.mybatis.support.MybatisGenericDao;
import com.ctsi.system.domain.DateChecker;
import com.ctsi.system.domain.DayCell;
import com.ctsi.system.domain.WorkCalendar;
import com.ctsi.system.interfaces.I_Calandar;
import com.ctsi.system.interfaces.I_WorkCalendar;
import com.ctsi.system.workcalendar.defdate.FreeDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zhangjw
 * @className WorkCalendarService
 * @description TODO
 * @date 2019/3/30 13:16
 **/
@Service
public class WorkCalendarService implements I_WorkCalendar, I_Calandar {
    private static final Logger log = LoggerFactory.getLogger(WorkCalendarService.class);

    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd-E");

    @Autowired
    private MybatisGenericDao dao;

    public static boolean equals(Calendar front, Calendar hehind) {
        if (front.get(Calendar.YEAR) != hehind.get(Calendar.YEAR)) {
            return false;
        }
        if (front.get(Calendar.MONTH) != hehind.get(Calendar.MONTH)) {
            return false;
        }
        return front.get(Calendar.DAY_OF_MONTH) == hehind.get(Calendar.DAY_OF_MONTH);

    }

    public static boolean before(WorkCalendar w1, WorkCalendar w2) {
        if (w2.getWorkYear() != w1.getWorkYear()) {
            return w2.getWorkYear() > w1.getWorkYear();
        }
        if (w2.getWorkMonth() != w1.getWorkMonth()) {
            return w2.getWorkMonth() > w1.getWorkMonth();
        }
        if (w2.getWorkDay() != w1.getWorkDay()) {
            return w2.getWorkDay() > w1.getWorkDay();
        }
        return false;
    }

    /**
     * 生成一年的日历
     *
     * @param y            年份
     * @param dataObjectId 数据对象，用于区分不同的日历用途
     */
    public void createWorkCalendarOneYear(int y, String dataObjectId) {
        // 读取假日
        FreeDateUtil ds = FreeDateUtil.INST;
        Calendar c = Calendar.getInstance();
        Calendar first = Calendar.getInstance();
        c.set(y, 0, 1);
        first.set(y, 0, 1);
        WorkCalendar wc = null;
        do {
            if (!ds.isFree(c)) {
                wc = new WorkCalendar(c, dataObjectId);
                dao.insert(WorkCalendar.class.getName() + ".insert", wc);
            }
            log.debug("日期:[{}]", sf.format(c.getTime()));
            c.roll(Calendar.DAY_OF_YEAR, true);
        } while (!WorkCalendarService.equals(first, c));
    }

    @Override
    public void createWorkCalendarOneYear(int y) {
        createWorkCalendarOneYear(y, null);
    }

    @Override
    public void save(int year, int month, String[] day) {
        String dataObjectId = null;
        try {
            save(year, month, day, dataObjectId);
        } catch (Exception e) {
            log.error("假日保存失败", e);
            throw new RuntimeException("假日保存失败", e);
        }
    }

    public void save(int year, int month, String[] day, String dataObjectId) throws Exception {
        WorkCalendar wc = new WorkCalendar();
        wc.setWorkYear(year);
        wc.setWorkMonth(month);
        wc.setDataObjectId(dataObjectId);
        dao.delete(WorkCalendar.class.getName() + ".delete", wc);
        SimpleDateFormat sf = new SimpleDateFormat(UtilDateTime.defaultDatePattern);

        Calendar c = Calendar.getInstance();
        Calendar first = Calendar.getInstance();
        c.set(wc.getWorkYear(), wc.getWorkMonth() - 1, 1);
        first.set(wc.getWorkYear(), wc.getWorkMonth() - 1, 1);
        loop:
        do {

            for (int i = 0; day != null && i < day.length; i++) {
                Calendar temp = Calendar.getInstance();
                temp.setTime(sf.parse(day[i]));
                if (WorkCalendarService.equals(c, temp)) {
                    c.roll(Calendar.DAY_OF_MONTH, true);
                    continue loop;
                }

            }

            wc = new WorkCalendar(c, dataObjectId);

            dao.insert(WorkCalendar.class.getName() + ".insert", wc);
            log.debug("工作日");

            log.debug("日期:[{}]", sf.format(c.getTime()));
            c.roll(Calendar.DAY_OF_MONTH, true);
        } while (!WorkCalendarService.equals(first, c));
    }

    @Override
    public void delete(int year) {
        String dataObjectId = null;
        WorkCalendar wc = new WorkCalendar();
        wc.setWorkYear(year);
        wc.setDataObjectId(dataObjectId);
        dao.delete(WorkCalendar.class.getName() + ".deleteyear", wc);
    }

    public DateChecker getDateChecher(Integer y, Integer m, String dataObjectId) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("workYear", y);
        map.put("workMonth", m);
        map.put("dateObjectId", dataObjectId);
        List<WorkCalendar> list = (List<WorkCalendar>) dao.queryForList(WorkCalendar.class.getName() + ".select", map);
        DateChecker dc = new DateChecker();
        dc.setList(list);
        return dc;
    }

    public DateChecker getDateChecher(Calendar calendar, String dateObjectId) {
        Map<String, Object> map = new HashMap<String, Object>();
        WorkCalendar wc = new WorkCalendar(calendar, dateObjectId);
        map.put("workYear", wc.getWorkYear());
        map.put("workMonth", wc.getWorkMonth());
        map.put("workDay", wc.getWorkDay());
        map.put("dateObjectId", wc.getDataObjectId());
        List<WorkCalendar> list = (List<WorkCalendar>) dao.queryForList(WorkCalendar.class.getName() + ".select", map);

        DateChecker dc = new DateChecker();
        dc.setList(list);
        return dc;
    }

    @Override
    public List<DayCell> getDateOneMonth(Integer y, Integer m) {
        String dateObjectId = null;
        DateChecker dc = getDateChecher(y, m, dateObjectId);
        Calendar fristDay = Calendar.getInstance();
        fristDay.set(y, m - 1, 1);
        log.info("first day is [{}]", fristDay.getTime());
        List<DayCell> list = new ArrayList<>();
        // 填充每月前空白部分
        int weekDay = fristDay.get(Calendar.DAY_OF_WEEK) == 1 ? 8 : fristDay.get(Calendar.DAY_OF_WEEK);
        for (int i = 2; i < weekDay; i++) {
            list.add(new DayCell());
        }

        // 填充月份
        Calendar c = Calendar.getInstance();

        c.set(y, m - 1, 1);
        c.setLenient(true);
        fristDay.setLenient(true);
        do {
            DayCell dcell = new DayCell(c);
            if (dc.test(dcell.getCalendar())) {
                dcell.setFree(true);
            }
            list.add(dcell);
            c.roll(Calendar.DAY_OF_MONTH, true);

        } while (!equals(fristDay, c));

        // 填充每月后空白
        c.roll(Calendar.DAY_OF_MONTH, false);
        weekDay = c.get(Calendar.DAY_OF_WEEK) == 1 ? 8 : c.get(Calendar.DAY_OF_WEEK);
        for (int i = weekDay + 1; i <= 8; i++) {
            list.add(new DayCell());
        }
        return list;
    }

    @Override
    public boolean isFree(java.util.Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        DateChecker dc = getDateChecher(calendar, null);
        return dc.test(calendar);
    }

    public int others2Days(java.util.Date date, long time, int type) {
        if (date == null || time == 0) {
            return 0;
        }
        SimpleDateFormat sf = new SimpleDateFormat(UtilDateTime.defaultDatePattern);
        String dt = sf.format(date) + " 00:00:00";
        sf = new SimpleDateFormat(UtilDateTime.defaultDateTimePattern);
        long n = 0;

        if (type == I_Calandar.DAY) {
            return (int) time;
        } else if (type == I_Calandar.HOUR) {
            n = 60 * 60 * 1000 * time;
        } else if (type == I_Calandar.MINUTES) {
            n = 60 * 1000 * time;
        } else if (type == I_Calandar.SECOND) {
            n = 1000 * time;
        } else if (type == I_Calandar.MS) {
            n = time;
        }
        long ms;
        try {
            ms = date.getTime() + n - sf.parse(dt).getTime();
        } catch (ParseException e) {
            log.error("日期转换错误", e);
            throw new RuntimeException("日期转换错误", e);
        }
        return (int) (ms / (24 * 60 * 60 * 1000));
    }

    private long getTimeLen(long time, int type) {
        long result = 0;
        switch (type) {
            case HOUR:
                result = 60 * 60 * 1000 * time;
                break;
            case MINUTES:
                result = 60 * 1000 * time;
                break;
            case SECOND:
                result = 1000 * time;
                break;
            case MS:
                result = time;
                break;
            default:
                throw new RuntimeException("not support type :" + type);
        }
        return result;
    }

    @Override
    public java.util.Date getWorkDate(java.util.Date date, long time, int type) {
        if (date == null) {
            throw new IllegalArgumentException("date is null");
        }
        if (type != DAY) {
            long timeLen = getTimeLen(time, type);
            if (timeLen < 60 * 60 * 1000 * 24) {
                log.info("time length {} < ont day", timeLen);
                return new java.util.Date(date.getTime() + timeLen);
            }
        }
        int n = others2Days(date, time, type);
        if (n <= 0) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        WorkCalendar w = new WorkCalendar(calendar, null);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("serialNo", date.getTime() - 24 * 60 * 60 * 1000);
        Page<WorkCalendar> pg = dao.pagedQuery(WorkCalendar.class.getName() + ".selectdate", map, 1, n + 2);
        List<WorkCalendar> list = pg.getResult();
        if (list.size() <= n) {
            log.warn("请求的时间超出设置的范围");
            calendar.add(Calendar.DAY_OF_YEAR, n);
            return calendar.getTime();
        }
        int num = 0;
        for (WorkCalendar wc : list) {
            if (before(w, wc)) {
                num++;
            }
            if (num >= n) {
                return new java.util.Date(wc.getSerialNo());
            }
        }
        throw new RuntimeException("计算时间错误");
    }

    @Override
    public int[] getDefinedYears() {
        List<Map> list = (List<Map>) dao.queryForList(WorkCalendar.class.getName() + ".selectDefinedYears");
        int[] ints = new int[list.size()];
        for (int i = 0; i < ints.length; i++) {
            ints[i] = Integer.parseInt(list.get(i).get("WORKYEAR").toString());
        }
        return ints;
    }


}
